package cn.edu.hitsz.compiler.parser;
import cn.edu.hitsz.compiler.NotImplementedException;
import cn.edu.hitsz.compiler.lexer.Token;
import cn.edu.hitsz.compiler.parser.table.Production;
import cn.edu.hitsz.compiler.parser.table.Status;
import cn.edu.hitsz.compiler.symtab.SourceCodeType;
import cn.edu.hitsz.compiler.symtab.SymbolTable;
import java.util.Stack;

// TODO: 实验三: 实现语义分析
public class SemanticAnalyzer implements ActionObserver {

    private SymbolTable symbolTable;
    private Stack<SemanticElement> semanticStack; // 使用栈保存语义信息

    public SemanticAnalyzer() {
        this.semanticStack = new Stack<>();
    }

    @Override
    public void whenAccept(Status currentStatus) {
        System.out.println("accept!");
    }

    @Override
    public void whenReduce(Status currentStatus, Production production) {
        // 根据production.index(),给归约的产生式附加动作
        switch (production.index()) {
            case 1: // P -> S_list
                SemanticElement sList=semanticStack.pop();
                System.out.println("Program start:\n" + sList.toString());
                break;

            case 2: // S_list -> S Semicolon S_list
                semanticStack.pop();
                semanticStack.pop();
                semanticStack.pop();
                semanticStack.push(new SemanticElement(production.head()));
                break;

            case 3: // S_list -> S Semicolon
                semanticStack.pop();
                semanticStack.pop();
                semanticStack.push(new SemanticElement(production.head()));
                break;

            case 4: // S -> D id
                //{p = lookup(id.name); if p != nil then enter(id.name, D.type) else error}
                SemanticElement id = semanticStack.pop();
                SemanticElement type = semanticStack.pop();
                if(!symbolTable.has(id.toString())){
                    symbolTable.add(id.toString());
                }
                symbolTable.setType(id.toString(),type.getType());
                semanticStack.push(new SemanticElement(production.head()));
                break;

            case 5: // D -> int
                semanticStack.pop();
                SemanticElement D=new SemanticElement(production.head(),SourceCodeType.Int);
                semanticStack.push(D);
                break;

            case 6: // S -> id = E
            case 8: // E -> E + A
            case 9: // E -> E - A
            case 11: // A -> A * B
            case 13: // B -> ( E )
                semanticStack.pop();
                semanticStack.pop();
                semanticStack.pop();
                semanticStack.push(new SemanticElement(production.head()));
                break;

            case 7: // S -> return E
                semanticStack.pop();
                semanticStack.pop();
                semanticStack.push(new SemanticElement(production.head()));
                break;


            case 10: // E -> A
            case 12: // A -> B
            case 14: // B -> id
            case 15: // B -> IntConst
                semanticStack.pop();
                semanticStack.push(new SemanticElement(production.head()));
                break;

            default:
                throw new NotImplementedException();

        }
    }

    @Override
    public void whenShift(Status currentStatus, Token currentToken) {
        // TODO: 该过程在遇到 shift 时要采取的代码动作
        semanticStack.push(new SemanticElement(currentToken));
    }

    @Override
    public void setSymbolTable(SymbolTable table) {
        // TODO: 设计你可能需要的符号表存储结构
        // 如果需要使用符号表的话, 可以将它或者它的一部分信息存起来, 比如使用一个成员变量存储
        symbolTable = table;
    }
}

